//=========================================================
// Vector functions

/** Sets all vector items to zero. */
void vec_clr(Val* v) {
	memset(obj_array(v)->data, 0, vec_num_bytes(v));
}

/** Creates a copy of a vector. Will also perform a shallow copy of an object,
	but will not increment the references. */
Val* vec_copy_impl(VM* vm, Val* v) {
	Val* r = vec_new(v->type, obj_count(v));
	assert(vec_num_bytes(r) == vec_num_bytes(v));
	memcpy(obj_begin(r), obj_begin(v), vec_num_bytes(v));
	return r;
}

/** Creates a new vector of the specified type and number of items. */
Val* vec_new_impl(VM* vm, int type, int count)
{
	Val* r;
	Array* a = (Array*)(calloc(1, sizeof(Array)));
	switch (type)
	{
		case ObjectType:	array_init(a, sizeof(Val*)); break;
		case VByteType:		array_init(a, sizeof(byte)); break;
		case VIntType:		array_init(a, sizeof(int)); break;
		case VFloatType:	array_init(a, sizeof(float)); break;
		case VDoubleType:	array_init(a, sizeof(double)); break;
		default: assert(!"not a recognized vector type"); return NULL;
	}
	array_alloc(a, count);
	a->cnt = count;
	r = val_new(type);
	obj_array(r) = a;
	return r;
}

/** Get the nth vector as a value. */
Val* vec_get_val_impl(Val* v, Val* x, int n) {
	assert(val_is_vec(v));
	switch (v->type)
	{
		case VByteType:		x->type = ByteType;		val_to_byte(x)		= vec_at(byte, v, n);	break;
		case VIntType:		x->type = IntType;		val_to_int(x)		= vec_at(int, v, n);	break;
		case VFloatType:	x->type = FloatType;	val_to_float(x)		= vec_at(float, v, n);	break;
		case VDoubleType:	x->type = DoubleType;	val_to_double(x)	= vec_at(double, v, n); break; 
		default: assert(!"not a recognized vector type"); return NULL;
	}
	return x;
}

/** Sets the nth vector as a value. */
void vec_set_val_impl(Val* v, Val* x, int n) {
	assert(val_is_vec(v));
	switch (v->type)
	{
		case VByteType:		vec_at(byte, v, n)		= val_to_byte(x);	break;
		case VIntType:		vec_at(int, v, n)		= val_to_int(x);	break; 
		case VFloatType:	vec_at(float, v, n)		= val_to_float(x);	break; 
		case VDoubleType:	vec_at(double, v, n)	= val_to_double(x); break; 
		default: assert(!"not a recognized vector type"); break; 
	}
}

/** Calls an op-code for every item in a vector. */
void vec_map_op(VM* vm, byte code) {
	int i = 0;
	Val* v = vm_top();
	int max = obj_count(v);
	for (; i < max; ++i) {
		vm_top() = vec_get_val(v, i);
		vm_eval(vm, code);
		vec_set_val(v, vm_top(), i);
	}
	vm_top() = v;
}

/** Call an op-code for every two corresponding items in two arrays. */
void vec_zip_op(VM* vm, byte code) {
	int i = 0;
	Val* v = vm_top();
	Val* w = vm_second();
	int max = obj_count(v) <= obj_count(w) ? obj_count(v) : obj_count(w);
	Val tmp;
	Val tmp2;
	vm_top() = &tmp;
	vm_second() = &tmp2;
	for (; i < max; ++i) {
		val_to_int(&tmp) = vec_at(int, v, i);
		vm_eval(vm, code);
		vec_at(int, v, i) = val_to_int(&tmp);
	}
	vm_top() = v;
	vm_second() = w;
}

